
function_decl = {};
enumeral_type = {};
record_type = {};
identifier_node = {};
type_decl = {};
union_type = {};
tree = {}
nameTable = {};
namespace_decl = {};
template_decl = {};

require("base");

function split(s,d)
    local t = {};
    local p = "(.-)"..d;
    s = s .. d;
    for match in s:gmatch(p) do
        table.insert(t,match);
    end
    return t;
end

function string.trim(s)
    return (s:gsub("^%s*(.-)%s*$", "%1"))
end

function parseField(s)
    s = s .. " "; --"type: @30     int: 0" \x00 
    local p = "([^ ]-.):(.-[^ ]) ";
    local t = {};
    for m,b in s:gmatch(p) do
        --table.insert(t,match);
        local key = m:trim();
        local value = b:trim();
        if(t[key])then
            if(type(t[key])=='string')then
                t[key] = {t[key]};
            end
            table.insert(t[key],value);
        else
            t[key] = value;
        end
        --t[m:trim()] = b:trim();
    end
    return t;
end

function parse(code)
    local array = split(code,"\n@");
    tree = {};
    local declMeta = NewDeclMetatable();
    --print(#array);
    for k,v in pairs(array)do
        local offset = v:find(" ");
        local id;
        if(k~=1)then
            id = "@" .. v:sub(1,offset-1);
        else
            id = v:sub(1,offset-1);
        end
        local typ = v:find("[^ ]",offset);
        local field = v:find(" ",typ);
        typ = v:sub(typ,field-1);
        local s = v:sub(field);
        field = parseField(s);
        field.code = typ;
        field.text = v;
        local t = field;
        if(t.code=="identifier_node")then
            if(t.note)then
                --c++ 
            else
                local l = tonumber(t.lngt);
                if(l~=#t.strg)then
                    local off = s:find("strg: ");
                    t.strg = s:sub(off + 6,off + 6 + l - 1);
                end
                nameTable[t.strg] = id;
            end
        end
        field.id = id;
        field.root = tree;
        tree[id] = field;
        setmetatable(field, declMeta);
    end
    for k,v in pairs(tree) do
        local t = _G[v.code];
        if(t)then
            --t[k] = tree[k];
            table.insert(t,tree[k]);
        end
    end
end

--解析翻译单元
function GetCppType(filter,namespace)
    if(template_decl_table==nil)then
        template_decl_table = {};
        for k,v in ipairs(template_decl)do
            v = v:GetDecl();
            if(v.name.strg)then
                --有时候是重载模板
                template_decl_table[v.name.strg] = v;
            end
        end
    end
    local list = {};
    if(filter==nil)then filter = ''; end;
    local types = type_decl;
    if(namespace)then
        types = {};
        for k,v in ipairs(namespace_decl)do
            v = v:GetDecl();
            if(v.name.strg==namespace)then
                local dcls = v.dcls;
                while(dcls)do
                    table.insert(types,dcls);
                    dcls = dcls.chain;
                end
            end
        end
    end

    for k,v in ipairs(types)do
        if(namespace==nil)then
            v = v:GetDecl();
        end
        if(v.code=='type_decl')then
            --如果是类型定义
            if(v.note=='artificial' or v.type.unql)then
                --cpp
                --v.type.unql  : 类型别名
                local name = v.name.strg;
                if(name and name:sub(1,#filter)==filter)then
                    table.insert(list,v);
                end
            end
        end
    end

    local function tolcname(name)
        return string.format('%d%s',#name,name);
    end

    local function setType(CXXType)
        function CXXType:GetLCName()
            local name = self.name.strg;  --类名
            local cxxname = name;         --cxx类名
            --遍历查找
            name = tolcname(name);
            local scpe = self.scpe;
            while(scpe)do
                if(scpe.code=='record_type' and scpe.scpe==nil)then
                    --type_decl
                    scpe = scpe.name;
                elseif(scpe.code~='translation_unit_decl' and scpe.name.strg==nil)then
                    scpe = scpe.name.scpe;
                end
                if(scpe.code=='translation_unit_decl')then
                    break;
                end
                cxxname = scpe.name.strg .. '::' ..cxxname;
                name = tolcname(scpe.name.strg)..name;
                scpe = scpe.scpe;
            end
            return '_'..name,cxxname;
        end
        function CXXType:GetTypeName()
            return self.name.strg;
        end
        function CXXType:GetBase()
            local self = self.type;
            if(self.base==nil)then
                return nil;
            end
            if(#self.base==0)then
                local base = self.base;
                base = base.name; --type_decl
                setType(base);
                return {base};
            else
                local list = {};
                for k,v in ipairs(self.base)do
                    local base = self.root[v]:GetDecl();
                    base = base.name; --type_decl
                    setType(base);
                    table.insert(list,base);
                end
                return list;
            end
        end
        function CXXType:GetUnqlType()
            local alias = {};
            while(self.type.unql)do
                table.insert(alias,self);
                self = self.type.unql.name;  --type_decl
            end
            setType(self);
            return self,alias;
        end
        function CXXType:GetMethods()
            local list = {};
            local classname = self:GetTypeName();
            --如果是类型别名,则要还原成类型别名
            self = self:GetUnqlType();
            local unclassname = self:GetTypeName();

            local fncs = self.type.fncs;
            if(fncs==nil)then return nil; end;
            while(true)do
                if(fncs==nil)then 
                    return list;
                end;

                local func = {};
                func.name = fncs.name.strg;
                if(unclassname==func.name)then
                    func.name = classname;
                end
                func.fncs = fncs;
                local nodump = false;
                
                if(fncs.accs~='pub' or fncs.type.clas==nil)then
                    --非共有方法
                    --静态方法
                    nodump = true;
                    
                end

                if(fncs.name.strg~=nil and nodump~=true)then --可能是重载符号
                    table.insert(list,func);
                    function func:GetLCName()
                        local fncs = self.fncs;
                        local fname = fncs.name.strg;
                        --获得本函数的结构体
                        local scpe = fncs.scpe;
                        if(scpe)then
                            local type = scpe.name;
                            local name = type.name.strg;
                            return string.format('_%d%s%d%s',#name,name,#fname,fname),self.name,name;
                        end
                    end
                    function func:GetLCParmType(id)
                        if(id==nil)then id = 1; end;
                        if(self.args[id])then
                            local valu = self.args[id];
                            local ref;
                            local ptr;
                            local record = valu;
                            if(valu.code=='reference_type')then
                                ref = 1;
                                record = valu.refd;
                            elseif(valu.code=='pointer_type')then
                                ptr = 1;
                                record = valu.ptd;
                            elseif(valu.code=='record_type')then
                                record = valu;
                            end
                            --可能会有其他类型
                            if(record)then
                                local code = record.code;
                                if(code=='integer_type')then
                                    if(ptr==1)then
                                        if(record.name and record.name.name)then --.name = type_decl
                                            if(record.name.name.strg=='char')then
                                                --char *
                                                return 'char_ptr',nil,ref;
                                            end
                                        end
                                    end
                                    return 'int',ptr,ref;
                                elseif(code=='real_type')then
                                    return 'float',ptr,ref;
                                elseif(code=='boolean_type')then 
                                    return 'bool',ptr,ref;
                                elseif(code=='void_type')then
                                    return 'void',ptr,ref;
                                elseif(code=='record_type')then
                                elseif(code=='enumeral_type')then
                                else
                                    return nil;
                                end
                                local type = record.name;
                                if(type.GetLCName==nil)then setType(type); end;
                                local name,cxxname = type:GetLCName();
                                if(template_decl_table[cxxname])then
                                    --如果是模板类型,则排除
                                    return nil;
                                end
                                return cxxname,ptr,ref,name;
                            end
                        end
                    end
                    local ret = fncs.type.retn;
                    local ref;
                    local ptr;
                    while(true)do
                        if(ret.code=='pointer_type')then
                            if(ptr==nil)then ptr=0; end;
                            ptr = ptr + 1;
                            ret = ret.ptd;
                        elseif(ret.code=='reference_type')then
                            if(ref==nil)then ref = 0; end;
                            ref = ref + 1;
                            ret = ret.refd;
                        else
                            break;
                        end
                    end
                    func.ret = ret.name;
                    setType(func.ret);
                    func.args = {};
                    --是否为构造函数
                    if(fncs.note=='constructor')then
                        func.isctor = true;
                    elseif(fncs.note=='destructor')then--析构函数
                        func.isdtor = true;
                    elseif(fncs.note)then --列表
                        for k,v in ipairs(fncs.note)do
                            if(v=='constructor')then
                                func.isctor = true;
                            elseif(v=='destructor')then
                                func.isdtor = true;
                            end
                        end
                    end

                    local tree_list = fncs.type.prms;
                    while(true)do
                        if(tree_list==nil)then
                            break;
                        end
                        setType(tree_list.valu);
                        table.insert(func.args,tree_list.valu);
                        tree_list = tree_list.chan;
                    end
                end
                fncs = fncs.chain;
            end
        end
    end

    for k,CXXType in ipairs(list)do
        setType(CXXType);
    end
    return list;
end


